#include <Eigen/Dense>
#include <iostream>

using namespace Eigen;
using std::cout, std::endl;

void test_normal_slice() {
  int n = 2;
  MatrixXd m2 = MatrixXd::Zero(6 * n, 6 * n);
  for (int i = 0; i < n; i++) {
    m2(6 * i, 6 * i) = 1;
    m2(6 * i + 1, 6 * i + 1) = 1;
    m2(6 * i + 2, 6 * i + 2) = 1;
    m2(6 * i + 3, 6 * i + 3) = 2;
    m2(6 * i + 4, 6 * i + 4) = 2;
    m2(6 * i + 5, 6 * i + 5) = 2;
  }
  cout << "m2 = \n" << m2 << endl;
}

void test_slice_block() {
  MatrixXd m1 = MatrixXd::Random(5, 5);
  cout << "m1 = \n" << m1 << endl;
  cout << "m1.block(0,0,3,4) = \n" << m1.block(0, 0, 3, 4) << endl;
  cout << "m1.block<3,4>(0,0) = \n" << m1.block<3, 4>(0, 0) << endl;

  // 对于稠密矩阵来说，结果是可读可写的
  MatrixXd m2 = MatrixXd::Constant(5, 5, 2);
  m2.block(0, 0, 3, 4) = Matrix<double, 3, 4>::Ones();
  cout << "m2 = \n" << m2 << endl;

  MatrixXd m3 = MatrixXd::Constant(5, 5, 2);
  m3.block<3, 4>(2, 1) = Matrix<double, 3, 4>::Ones();
  cout << "m3 = \n" << m3 << endl;
}

void test_special_slice() {
  MatrixXd m4 = MatrixXd::Random(5, 5);
  cout << "m4 = \n" << m4 << endl;
  cout << "m4.col(1) = \n" << m4.col(1) << endl;
  cout << "m4.row(1) = \n" << m4.row(1) << endl;

  RowVectorXd m5 = RowVectorXd::Random(6);
  cout << "m5 = \n" << m5 << endl;
  cout << "m5.head(4) = \n" << m5.head(4) << endl;
  cout << "m5.tail(4) = \n" << m5.tail(4) << endl;
  cout << "m5.segment(1,4) = \n" << m5.segment(1, 4) << endl;

  cout << "m4.totLeftCorner(3,4) = \n" << m4.topLeftCorner(3, 4) << endl;
  cout << "m4.bottomLeftCorner(3,4) = \n" << m4.bottomLeftCorner(3, 4) << endl;
  cout << "m4.topRightCorner(3,4) = \n" << m4.topRightCorner(3, 4) << endl;
  cout << "m4.bottomRightCorner(3,4) = \n"
       << m4.bottomRightCorner(3, 4) << endl;
}

void test_slice_with_rows_and_cols() {
  MatrixXd m1 = MatrixXd::Random(5, 5);
  Vector3i v1 = (Vector3i() << 1, 3, 4).finished();
  Array3i a1 = (Array3i() << 1, 3, 4).finished();
  int N[3] = {1, 3, 4};
  cout << "m1 = \n" << m1 << endl << endl;
  cout << "m1(v1, v1) = \n" << m1(v1, v1) << endl;
  cout << "m1(a1, a1) = \n" << m1(a1, a1) << endl;
  cout << "m1(N, N) = \n" << m1(N, N) << endl;
}
void test_slice_with_seq_and_seqN() {
  // seq(2,5) => {2,3,4,5}
  // seq(2,8,2) => {2,4,6,8}
  // seqN(2,5) => {2,3,4,5,6}
  // seqN(2,3,2) => {2,5,8}

  MatrixXd m2 = MatrixXd::Zero(6, 6);
  for (int i = 0; i < 6; i++) {
    m2.col(i) << i, i, i, i, i, i;
  }
  cout << "m2 = \n" << m2 << endl << endl;

  cout << "m2(seq(0,4,2), seqN(1,3,2)) = \n"
       << m2(seq(0, 4, 2), seqN(1, 3, 2)) << endl;
}
int main() {
  test_normal_slice();
  test_slice_block();
  test_special_slice();

  test_slice_with_rows_and_cols();
  test_slice_with_seq_and_seqN();
  return 0;
}